using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Windows.Forms;
using System.Reflection;
using Camalon.ColorPicker.Properties;

namespace Camalon.ColorPicker
{
	/// <summary>
	/// Summary description for ColorPanel.
	/// </summary>
	internal class ColorSpace : System.Windows.Forms.Control
	{
		/// <summary> 
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		private ColorWheelHelper _colorWheel;
		private Cursor _cursor;
		public ColorSpace()
		{
			this.SetStyle( ControlStyles.AllPaintingInWmPaint, true);
			this.SetStyle( ControlStyles.DoubleBuffer,true);
			this.SetStyle( ControlStyles.UserPaint, true );

			// TODO: Add any initialization after the InitializeComponent call
			// This call is required by the Windows.Forms Form Designer.
			InitializeComponent();

			this.Size = new Size( 256,256);
			SetClientSizeCore(256,256);


			Rectangle r = this.ClientRectangle;
			r.Width--;r.Height--;
            _colorWheel = new ColorWheelHelper(r);
			_colorWheel.HSB = ColorRenderingValue.HSB;
			
			ColorRenderingValue.ColorRangeChanged+=new EventHandler(ColorRenderingHelper_ColorRangeChanged);
			ColorRenderingValue.ValueChanged+=new EventHandler(ColorRenderingHelper_ValueChanged);
			

		}



		/// <summary> 
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}


		#region Component Designer generated code
		/// <summary> 
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			// 
			// ColorPanel
			// 
			this.Name = "ColorPanel";
			this.Size = new System.Drawing.Size(256, 256);

		}
		#endregion


		private bool _showWheel;
		public void ShowWheel( bool show )
		{
			if( _showWheel == show ) return;

			_showWheel = show;
			_colorPoint = CalculatePoint();
			this.Invalidate();
		}


		private void ColorRenderingHelper_ColorRangeChanged(object sender, EventArgs e)
		{
			_colorPoint = CalculatePoint();
			
			this.Invalidate();
		}

		private bool _colorRenderingHelperValueChanging;
		private void ColorRenderingHelper_ValueChanged(object sender, EventArgs e)
		{
			if( _colorRenderingHelperValueChanging ) return;
			_colorPoint = CalculatePoint();
			this.Invalidate();
		}

		private const int GRIP_OFFSET = 6;

		private Rectangle PathRect
		{
			get
			{ 
				Rectangle rect = new Rectangle( _colorPoint, new Size( 2*GRIP_OFFSET,2*GRIP_OFFSET));
				rect.X -= GRIP_OFFSET;
				rect.Y -= GRIP_OFFSET;
				return rect;
			}
		}
		private Point _colorPoint = new Point( 128,128 );

		protected override void OnMouseDown(MouseEventArgs e)
		{
			this.Focus();
			if( e.Button == MouseButtons.Left)
			{
				Point value = new Point(e.X, e.Y);
				if( value.X > 255) value.X = 255;
				if( value.X < 0) value.X = 0;
				if( value.Y > 255) value.Y = 255;
				if( value.Y < 0) value.Y = 0;
				
				CalculateColor( value);
			}

			base.OnMouseDown (e);
		}



		protected override void OnMouseMove(MouseEventArgs e)
		{
            if( _cursor == null) _cursor = new Cursor(new System.IO.MemoryStream( Resources.MouseTracker));
			if( this.Cursor != _cursor ) this.Cursor = _cursor;

            if( e.Button == MouseButtons.Left)
			{

				Point value = new Point(e.X, e.Y);
				if( value.X > 255) value.X = 255;
				if( value.X < 0) value.X = 0;
				if( value.Y > 255) value.Y = 255;
				if( value.Y < 0) value.Y = 0;
				
				CalculateColor( value);
			}

			base.OnMouseMove (e);
		}


		private void CalculateRectColor( Point p )
		{

			if( ColorRenderingValue.ColorRange == ColorRange.None) return;// Color.Empty;

			_colorPoint = p;

			p.Y = 255 - p.Y;


			if( ColorRenderingValue.ColorRange == ColorRange.Red || ColorRenderingValue.ColorRange == ColorRange.Green||ColorRenderingValue.ColorRange== ColorRange.Blue)
			{
				if ( ColorRenderingValue.ColorRange == ColorRange.Red ) 
				{
					ColorRenderingValue.Green	= p.Y;
					ColorRenderingValue.Blue	= p.X;
				}
				else if ( ColorRenderingValue.ColorRange == ColorRange.Green )
				{
					ColorRenderingValue.Red		= p.Y;
					ColorRenderingValue.Blue	= p.X;
				}
				else if ( ColorRenderingValue.ColorRange == ColorRange.Blue ) 
				{
					ColorRenderingValue.Green	= p.Y;
					ColorRenderingValue.Red		= p.X;
				}
			}
			else
			{
				if ( ColorRenderingValue.ColorRange == ColorRange.Hue ) 
				{
					int brightness = ( int ) Math.Round( (double)p.Y / 2.55 );
					int saturation = ( int ) Math.Round( (double)p.X / 2.55 );

					ColorRenderingValue.Saturation = saturation;
					ColorRenderingValue.Brightness = brightness;

				} 
				else if ( ColorRenderingValue.ColorRange == ColorRange.Saturation ) 
				{
					int hue = ( int ) Math.Round( (double)p.X * 360.0 / 255.0  );
					int brightness = ( int ) Math.Round( (double)p.Y  / 2.55 );

					ColorRenderingValue.Hue		= hue;
					ColorRenderingValue.Brightness = brightness;

				}
				else if ( ColorRenderingValue.ColorRange == ColorRange.Brightness ) 
				{
					int hue = ( int ) Math.Round( (double)p.X * 360.0 / 255.0  );
					int saturation = ( int ) Math.Round( (double)p.Y  / 2.55 );
					ColorRenderingValue.Hue		= hue;
					ColorRenderingValue.Saturation = saturation;

				}
			}

		}

		private void CalculateWheelColor( Point p )
		{
			_colorWheel.ColorPoint	= p;
			ColorRenderingValue.HSB = _colorWheel.HSB;
			_colorPoint				= Point.Round(_colorWheel.ColorPoint);
		}

		private void CalculateColor( Point p ) 
		{
			_colorRenderingHelperValueChanging = true;

			Rectangle oldRect = this.PathRect;
			oldRect.Inflate( 2,2 );
			
			if(_showWheel) CalculateWheelColor(p);
			else CalculateRectColor(p);

			Rectangle rect = this.PathRect;
			rect.Inflate( 2,2 );
			this.Invalidate( oldRect );
			this.Invalidate( rect );

			_colorRenderingHelperValueChanging = false;
		}


		private static Point CalculateRectPoint()
		{

			int x = 0;
			int y = 0;

			if( ColorRenderingValue.ColorRange == ColorRange.Red || 
				ColorRenderingValue.ColorRange == ColorRange.Green||
				ColorRenderingValue.ColorRange == ColorRange.Blue)
			{
				//RGB
				if ( ColorRenderingValue.ColorRange == ColorRange.Red ) 
				{
					x = ColorRenderingValue.Blue;
					y = ColorRenderingValue.Green;
				}					
				else if ( ColorRenderingValue.ColorRange == ColorRange.Green )
				{
					x = ColorRenderingValue.Blue;
					y = ColorRenderingValue.Red;
				}					
				else if ( ColorRenderingValue.ColorRange == ColorRange.Blue ) 
				{
					x = ColorRenderingValue.Red;
					y = ColorRenderingValue.Green;	
				}
			}
			else
			{
				if ( ColorRenderingValue.ColorRange == ColorRange.Hue ) 
				{
					x = ( int ) Math.Round( (double)ColorRenderingValue.Saturation * 2.55 );
					y = ( int ) Math.Round( (double)ColorRenderingValue.Brightness * 2.55 );
				} 
				else if ( ColorRenderingValue.ColorRange == ColorRange.Saturation ) 
				{
					x = ( int ) Math.Ceiling( ColorRenderingValue.Hue * ( 255.0 / 360.0 ) );
					y = ( int ) ((double)ColorRenderingValue.Brightness * 2.55  );
				}
				else if ( ColorRenderingValue.ColorRange == ColorRange.Brightness ) 
				{
					x = ( int ) Math.Ceiling( (double)ColorRenderingValue.Hue * ( 255.0 / 360.0 ) );
					y = ( int ) Math.Round( (double)ColorRenderingValue.Saturation * 2.55 );
				}
			}

			y = 255 - y;

			return new Point( x, y);

		}
		
		private Point CalculateWheelPoint()
		{
			_colorWheel.HSB = ColorRenderingValue.HSB;
			return Point.Round(_colorWheel.ColorPoint);
		}

		private Point CalculatePoint()
		{
			if( ColorRenderingValue.ColorRange == ColorRange.None) return Point.Empty;

			if( _showWheel) return CalculateWheelPoint();
			else return CalculateRectPoint();
		}


		#region DRAWING
		private static Bitmap _gradientBitmap;
		private static void DrawGreenColorField( Graphics g , int green ) 
		{
			
			int red = 255;
			Rectangle rect;
			
			for ( int i=0; i < 256; i++ ) 
			{
				rect = new Rectangle( 0, i, 256, 1 );
								
				using ( LinearGradientBrush lgb = new LinearGradientBrush( 
							rect, 
							Color.FromArgb( red, green, 0 ), 
							Color.FromArgb( red, green, 255 ), 
							LinearGradientMode.Horizontal ) )
					g.FillRectangle( lgb, rect );

				red--;

			}

		}
		
		private static void DrawBlueColorField( Graphics g, int blue ) 
		{

			int green = 255;
			Rectangle rect;
				
			for ( int i=0; i < 256; i++ ) 
			{
							
				rect = new Rectangle( 0, i, 256, 1 );

				using ( LinearGradientBrush lgb = new LinearGradientBrush( 
							rect, 
							Color.FromArgb( 0, green, blue ), 
							Color.FromArgb( 255, green, blue ), 
							LinearGradientMode.Horizontal ) ) 
				{
					g.FillRectangle( lgb, rect );
				}

				green--;
				
			}
		
		}		

		private static void DrawRedColorField( Graphics g, int red ) 
		{
						
			int green = 255;
			Rectangle rect;
			
			for ( int i=0; i < 256; i++ ) 
			{
					
				rect = new Rectangle( 0, i, 256, 1 );

				using ( LinearGradientBrush lgb = new LinearGradientBrush( 
							rect, 
							Color.FromArgb( red, green, 0 ), 
							Color.FromArgb( red, green, 255 ), 
							0f, false ) )
					g.FillRectangle( lgb , new Rectangle( 0, i, 256, 1 ) );


				green--;
				
			}
						
		}
		private static void DrawHueColorField( Graphics g , int hue) 
		{
			Color endColor		=  ColorConverter.HsbToColor( new HSB( hue, 100, 100));
			double redIndex		= ( double ) ( 255 - endColor.R ) / 255;
			double blueIndex	= ( double ) ( 255 - endColor.B ) / 255;
			double greenIndex	= ( double ) ( 255 - endColor.G ) / 255;		

			double cR = 255;
			double cG = 255;
			double cB = 255;
	
			for ( int x=0; x < 256; x++ ) 
			{
							
				using ( LinearGradientBrush lgb = new LinearGradientBrush( 
							new Rectangle( x, 0, 1, 256 ), 
							Color.FromArgb( ( int ) Math.Round( cR ), 
							( int ) Math.Round( cG ), 
							( int ) Math.Round( cB ) ), 
							Color.FromArgb( 0, 0, 0 ), 
							90f, false ) ) 
					g.FillRectangle( lgb, new Rectangle( x, 0, 1, 256 ) );

				cR = cR - redIndex;
				cG = cG - greenIndex;
				cB = cB - blueIndex;

			}
				
		}

		private static void DrawSaturationColorField( Graphics g, int saturation ) 
		{

			Rectangle rect = new Rectangle( 0, 0, 256, 256 );
			int saturatedColorValue = ( int )( 255 - Math.Round( 255 * ( ( double ) saturation / 100 ) ) );

			if ( _gradientBitmap == null ) _gradientBitmap = DrawMultiGradientBitmap();
			

			g.DrawImage( _gradientBitmap, 0, 0 );

			Color startColor = Color.FromArgb( saturatedColorValue, 255, 255, 255 );
			using ( LinearGradientBrush lgb = new LinearGradientBrush( rect, startColor, Color.Black, 90f ) ) 
				g.FillRectangle( lgb, rect );
			
			
			
		}

		private static void DrawBrightnessColorField( Graphics g, int brightness ) 
		{

			int alpha = ( int )( 255 - Math.Round( brightness * 2.55 ) );
			
			if ( _gradientBitmap == null ) _gradientBitmap = DrawMultiGradientBitmap();
			

			g.DrawImage( _gradientBitmap, 0, 0 );

			using ( SolidBrush sb = new SolidBrush( Color.FromArgb( alpha, 0, 0, 0 ) ) ) 
				g.FillRectangle( sb, 0, 0, 256, 256 );
			

		}

		private static Bitmap DrawMultiGradientBitmap() 
		{

			Rectangle rect;
			int colorValue = 255;
			Bitmap bmp = new Bitmap( 256, 256 );

			using ( Graphics gBmp = Graphics.FromImage( bmp ) ) 
			{

				for ( int i=0; i < 256; i++ ) 
				{
					rect = new Rectangle( 0, i, 256, 1 );

					using ( LinearGradientBrush hueSliderBrush = new LinearGradientBrush( rect, Color.Blue, Color.Red, 0f, false ) ) 
					{

						Color[] colorArray = {	
												 Color.FromArgb( colorValue, i, i ), // red 
												 Color.FromArgb( colorValue, colorValue, i ), // yellow 
												 Color.FromArgb( i, colorValue, i ), // green 
												 Color.FromArgb( i, colorValue, colorValue ), // cyan 
												 Color.FromArgb( i, i, colorValue ), // blue 
												 Color.FromArgb( colorValue, i, colorValue ), // magneta
												 Color.FromArgb( colorValue, i, i ) // red
											 };

						float[] posArray = { 0.0f, 0.1667f, 0.3372f, 0.502f, 0.6686f, 0.8313f, 1.0f };

						ColorBlend colorBlend = new ColorBlend();
						colorBlend.Colors = colorArray;
						colorBlend.Positions = posArray;
						hueSliderBrush.InterpolationColors = colorBlend;

						gBmp.FillRectangle( hueSliderBrush, rect );
					}
				}
					
			} 

			return bmp;

		}

		private static void DrawColorField( Graphics g )
		{
			ColorRange colorRange = ColorRenderingValue.ColorRange;
			//Drawing rect area of 256x256
			if( colorRange == ColorRange.None) return;

			if( colorRange == ColorRange.Red || colorRange == ColorRange.Green||colorRange == ColorRange.Blue)
			{
				//RGB
				RGB rgb = ColorRenderingValue.RGB;
				if ( colorRange == ColorRange.Red )		DrawRedColorField( g, rgb.Red );											
				if ( colorRange == ColorRange.Green )	DrawGreenColorField( g, rgb.Green);											
				if ( colorRange == ColorRange.Blue ) 	DrawBlueColorField( g, rgb.Blue );						
			}
			else
			{
				//HSB
				HSB hsb = ColorRenderingValue.HSB;
				if ( colorRange == ColorRange.Hue )			DrawHueColorField( g, hsb.Hue );
				if ( colorRange == ColorRange.Saturation )	DrawSaturationColorField( g, hsb.Saturation);						
				if ( colorRange == ColorRange.Brightness )	DrawBrightnessColorField( g,hsb.Brightness );
			}

		}


       


		protected override void OnPaint(PaintEventArgs e)
		{
			if( ColorRenderingValue.ColorRange == ColorRange.None) return;


			if(!_showWheel)		DrawColorField( e.Graphics );
			else 
			{
                e.Graphics.DrawImage(_colorWheel.ColorImage, _colorWheel.ColorRectangle);//this.ClientRectangle); // 
				
				int opacity = 255 - (int)((double)ColorRenderingValue.Brightness * 2.55);
				Color c = Color.FromArgb( opacity, Color.Black);
				using ( SolidBrush b = new SolidBrush( c ))
				{
					e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
					Rectangle r = this.ClientRectangle;
					r.Width--;r.Height--;
					e.Graphics.FillEllipse( b, r);
					using ( Pen p = new Pen( Color.White, 1f))
					e.Graphics.DrawEllipse( p, r );
				}

				e.Graphics.Clip = _colorWheel.ColorRegion;
			}



			//Draw Grip
			Rectangle rect = this.PathRect;
			e.Graphics.DrawEllipse( Pens.Black, rect );
			rect.Inflate( -1,-1);
			e.Graphics.DrawEllipse( Pens.White, rect );
			
			e.Graphics.ResetClip();
		}

        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            using (SolidBrush brush = new SolidBrush(this.Parent.BackColor))
                pevent.Graphics.FillRectangle(brush, this.ClientRectangle);
        }


		#endregion DRAWING


	}
}
